package patterns

import (
	"fmt"
	"time"
)

func TryOrChannel1() {
	var or func(channels ...<-chan interface{}) <-chan interface{}
	or = func(channels ...<-chan interface{}) <-chan interface{} {
		switch len(channels) {
		case 0:
			return nil
		case 1:
			return channels[0]
		}

		terminated := make(chan interface{})
		go func() {
			defer close(terminated)
			switch len(channels) {
			case 2:
				select {
				case <-channels[0]:
				case <-channels[1]:
				}
			default:
				select {
				case <-channels[0]:
				case <-channels[1]:
				case <-channels[2]:
				case <-or(append(channels[3:], terminated)...):
				}
			}
		}()

		return terminated
	}

	sig := func(after time.Duration) <-chan interface{} {
		c := make(chan interface{})
		go func() {
			defer close(c)
			time.Sleep(after)
		}()
		return c
	}
	start := time.Now()
	<-or(sig(2*time.Hour), sig(5*time.Minute), sig(1*time.Second), sig(1*time.Hour), sig(1*time.Minute))
	fmt.Printf("done after %v", time.Since(start))
}

func TryOrChannel2() {
	var or func(channels ...<-chan interface{}) <-chan interface{}
	or = func(channels ...<-chan interface{}) <-chan interface{} {
		if len(channels) == 0 {
			return nil
		}

		terminated := make(chan interface{})
		go func() {
			defer close(terminated)
			switch len(channels) {
			case 1:
				<-channels[0]
			default:
				select {
				case <-channels[0]:
				case <-channels[1]:
				case <-or(append(channels[2:], terminated)...):
				}
			}
		}()

		return terminated
	}

	sig := func(after time.Duration) <-chan interface{} {
		c := make(chan interface{})
		go func() {
			defer close(c)
			time.Sleep(after)
		}()
		return c
	}
	start := time.Now()
	<-or(sig(2*time.Hour), sig(5*time.Minute), sig(1*time.Second), sig(1*time.Hour), sig(1*time.Minute))
	fmt.Printf("done after %v", time.Since(start))
}
